<cfcomponent displayname="CrafterCollection" output="no" accessors="yes">
	
	
	<!--- Properties --->
	<cfproperty name="collection" type="array" />
	<cfproperty name="collectionName" type="string" />
	<cfproperty name="collectionLength" type="numeric" />


	<!--- init() --->
	<cffunction name="init" access="public" returntype="any" output="no">
		<cfargument name="collectionName" type="string" required="no" default="" />
		<cfscript>
			setCollection(ArrayNew(1));
			setCollectionName(arguments.collectionName);
			setCollectionLength(0);
			return this;
		</cfscript>
	</cffunction>
	
	
	<!--- load() --->
	<cffunction name="load" access="public" returntype="any" output="no">
		<cfargument name="collection" type="array" required="yes" />
		<cfset setCollection(arguments.collection) />
	</cffunction>
	
	
	<!--- setCollection() --->
	<cffunction name="setCollection" access="public" output="no" returntype="any" hint="">
		<cfargument name="collection" type="array" required="yes" />
		<cfscript>
			variables.collection = arguments.collection;
			setCollectionLength(ArrayLen(arguments.collection));
		</cfscript>
	</cffunction>
	
	
	<!--- getIterator() --->
	<cffunction name="getIterator" access="public" output="no" returntype="any" hint="The collection itself is managed as an array. As such, it has a Java-type iterator object that can be used to loop over it.  This method is a wrapper to retrive that object.">
		<cfreturn getCollection().iterator() />
	</cffunction>

	
	<!--- getEffectiveLength() --->
	<cffunction name="getEffectiveLength" access="public" returntype="numeric" output="no" hint="This is a utility method for applications using the collection.  Provide the method with the number of items you want to output and it will return the most sensible length for you.">
		<cfargument name="nAttemptedLength" type="numeric" required="yes" />
		<cfscript>
			// If the attempted length is greater than the actual collection length
			// we can use use the collection length safely without going over.
			if (arguments.nAttemptedLength GT getCollectionLength()) {
				return getCollectionLength();
			}
			
			// Otherwise, use the attempted length.
			else {
				return arguments.nAttemptedLength;
			}
		</cfscript>
	</cffunction>
	
	
	<!--- getItem() --->
	<cffunction name="getItem" access="public" returntype="any" hint="Given an index it returns the item at that index." output="no">
		<cfargument name="index" type="any" required="yes" />
		<cfreturn getCollection()[arguments.index] />
	</cffunction>
	
	
	<!--- lazyGetItem() --->
	<cffunction name="lazyGetItem" access="public" returntype="any" hint="Given an index it returns the item at that index." output="no">
		<cfargument name="index" type="any" required="yes" />
		<cfreturn getCollection()[arguments.index] />
	</cffunction>
	
	
	<!--- setItem() --->
	<cffunction name="setItem" access="public" returntype="any" hint="" output="no">
		<cfargument name="index" type="any" required="yes" />
		<cfargument name="item" type="any" required="yes" />
		<cfset getCollection()[arguments.index] = arguments.item />
	</cffunction>

	
	<!--- addToCollection() --->
	<cffunction name="addToCollection" access="public" returntype="void" hint="Takes any piece of data and appends it to the collection." output="no">
		<cfargument name="item" type="any" required="yes" />
		<cfscript>
			// Append the item to the array and adjust the collection length value.
			try {
				ArrayAppend(getCollection(),arguments.item);
				setCollectionLength(ArrayLen(getCollection()));
			}
			catch(Any e) {
				writedump(getCollectionLength());
				writedump(arguments.item);abort;
			}
		</cfscript>
	</cffunction>
	
	
	<!--- removeFromCollection() --->
	<cffunction name="removeFromCollection" access="public" returntype="void" hint="Given an index, it removes the item at that index from the collection." output="no">
		<cfargument name="index" type="numeric" required="yes" />
		<cfscript>
			// Remove the item from the array and adjust the collection length value.
			ArrayDeleteAt(getCollection(),index);
			setCollectionLength(ArrayLen(getCollection()));
		</cfscript>
	</cffunction>
	
	
	<!--- limit() --->
	<cffunction name="limit" access="public" returntype="any" output="no" hint="Takes the collection and shortens it to the desired limit.">
		<cfargument name="limit" type="numeric" required="yes" />
		<cfscript>
		
			// Create an empty array to hold the new data
			local.arLimitedCollection = ArrayNew(1);
			
			// Given the limit being passed in and the actual size of the
			// collection, determine the effective limit
			local.nEffectiveLimit = getEffectiveLength(arguments.limit);
			
			// Loop from 1 to the effective limit, copying the items over.
			for (local.i = 1; local.i LTE local.nEffectiveLimit; local.i++) {
				ArrayAppend(local.arLimitedCollection,getItem(i));
			}
			
			// Replace the collection and update length property
			setCollection(local.arLimitedCollection);
			
		</cfscript>
	</cffunction>
	
	
	<!--- sort() --->
	<cffunction name="sort" access="public" returntype="any" hint="" output="no">
		<cfargument name="direction" type="string" required="yes" />
		<cfscript>
			
			// Create an empty array for our re-ordered collection
			local.arSortedCollection = ArrayNew(1);
			
			// Create a structure of settings for the reordering loop
			local.stSortSettings = {
				ASC = {
					FROM = 1,
					TO = getCollectionLength(),
					STEP = 1
				},
				DESC = {
					FROM = getCollectionLength(),
					TO = 1,
					STEP = -1	
				}
			};
			
			// Select the specific sort settings
			local.stSelectedSort = Evaluate("local.stSortSettings.#arguments.direction#");

		</cfscript>
		
		<cfloop from="#local.stSelectedSort['FROM']#" to="#local.stSelectedSort['TO']#" index="local.i" step="#local.stSelectedSort['STEP']#">
			<cfset ArrayAppend(local.arSortedCollection,lazyGetItem(i)) />
		</cfloop>
		<cfset setCollection(local.arSortedCollection) />
	</cffunction>
	
	
	<!--- replaceCollection() --->
	<cffunction name="replaceCollection" access="public" returntype="any" hint="" output="no">
		<cfargument name="collection" type="array" required="yes" />
		<cfscript>
			setCollection(arguments.collection);
			return this;
		</cfscript>
	</cffunction>
	
	
	<!--- join() --->
	<cffunction name="join" access="public" returntype="any" hint="" output="no">
		<cfargument name="oCollection" type="any" required="yes" />
		<cfscript>
			local.arWorkingCollection = getCollection();
			local.arWorkingCollection.addAll(arguments.oCollection.getCollection());
			setCollection(local.arWorkingCollection);
			return this;
		</cfscript>
	</cffunction>
	
	
	<!--- getAsJSON() --->
	<cffunction name="getAsJSON" access="public" returntype="string" output="no">
		<cfreturn SerializeJson(getCollection()) />
	</cffunction>
	
	
	
</cfcomponent>